<template>
  <div>
    <h1>ref</h1>
    <!-- ref的作用：
      1、ref 可以获取dom元素；
      2、ref  可以获取子组件对象，实现子传父 传值。
      3、ref  在vue3 中，将基本数据类型的数据用ref（）包裹起来转换成ref对象，成响应式数据
    -->

    <!-- 
        使用ref，想要获得具体的值，一定要注意生命周期的执行顺序。
        第一个  ref 在vue3中获取dom元素 
          实现步骤：
                  1、创建dom元素，添加ref标识；例：test
                  2、创建同名变量，并返回。 在setup函数中。  不返回就是undefined; 必须同名，同名是识别标识的依据。
                  3、ref声明的变量当中就是我们的dom元素。
          拿到具体的值：
                  受到生命周期执行顺序的影响，无法在 setup函数中直接获取，所以通过事件的方式获得。
          注意：  
                  在ts当中，函数调用时，如果函数定义了数据类型，调用时需要指定数据类型。
    -->
    <ul>
      <li ref="test">这是第一个li元素</li>
    </ul>
    <button @click="showTest">点击 查看test的value值</button>

    <!-- 
        第二个  ref获取子组件标签，实现子向父传值
          实现步骤：
                  1、创建子组件标签，加上ref标识；
                  2、创建同名变量，并返回。
                  3、ref声明的变量，就是子组件对象。
          拿到具体的值：
                  子组件对象中的值不能直接拿，要放到函数中去获取。
                  受生命周期执行顺序的影响。得在页面中通过dom元素事件去触发获取
          注意：  
                  在ts当中，函数调用时，如果函数定义了数据类型，调用时需要指定数据类型。
    -->
    <Son ref="sonRef"></Son>
    <button @click="sonMsg">点击查看子组件传过来的msg</button>

    <!-- 
      第三个  ref 添加到 v-for 动态的创建的标签上
    
    -->
    <ul>
      <li :ref:HTMLElement='getList' v-for="index in 10" :key="index">这是第{{index}}个li</li>
    </ul>
    <button @click="getDomEle">点击出现 具体的li</button>
  </div>
</template>

<script lang="ts">
//defineComponent 是一个函数，作用就是定义一个组件，在内部传入对象，配置对象

import { defineComponent, ref, reactive, computed, watch, watchEffect } from 'vue';
//引入组件
import Son from './components/Son.vue'

export default defineComponent({
  name: 'App',
  components: { Son },
  setup() {
    //第一个：获取dom元素
    //被ref标记的，要么就是没有(undefined)，要么就是dom元素。
    //dom元素的数据类型  HTMLElement
    //有可能获取不到  所以 加上了一个  null
    const test = ref<HTMLElement | null>();//注意ref是函数
    console.log(test) //ref 对象
    // console.log(test.value) //undefined  生命周期问题  因为setup函数的执行是在beforeCreate 之前  这时候，是拿不到dom元素的。
    //点击查看test.value
    function showTest() {
      console.log(test.value)
    }

    //第二个：获取子组件标签
    //组件如何指定数据类型：<InstanceType<typeof 组件名>>
    const sonRef = ref<InstanceType<typeof Son>>();
    console.log(sonRef);//ref 对象 -- 子组件对象
    // console.log(sonRef.value);//undefined 
    //子组件对象中具体的属性值，不能直接获取，得通过函数获取
    //还要注意一个： 注意生命周期执行顺序
    const sonMsg = () => {
      console.log(sonRef.value?.msg)//因为对象可有可无，所以加?
    }
    // function sonMsg(){
    //   console.log(sonRef.value?.msg)
    // }


    //第三个  获取v-for循环的多个ref dom节点
    const getDom:HTMLElement[] = [] //创建空数组 该数组用来存放 li
    const getList = (el:HTMLElement)=>{ //el 就是ref标记的那些dom元素
      getDom.push(el)
    }
    // console.log(getDom[1]) // undefined  还是生命周期执行顺序的问题
    function getDomEle(){
      console.log(getDom[1]) //dom元素
    }
    return {
      test,
      showTest,
      sonRef,
      sonMsg,
      getList,
      getDomEle
    }
  },
  mounted() {
    // console.log(this.$refs.test) // proxy 对象
  }


});
</script>

<style>

</style>
